#region Using

using System;
using System.Collections.Generic;

#endregion

namespace BlogEngine.Core
{
	/// <summary>
	/// RelatableBase extends Publishable base by implementing Next, Previous, First and Last
    /// properties.  
	/// </summary>
	[Serializable]
	public abstract class RelateableBase<T> : PublishableBase<T> where T : RelateableBase<T>, new()
	{

		#region Constructor

		/// <summary>
		/// The default contstructor assign default values.
		/// </summary>
		protected RelateableBase() :base()
		{
		}

		#endregion

		#region Properties

        /// <summary>
        /// Gets the first item of the collection.
        /// </summary>
        public T First
        {
            get
            {
                if (RelateableBase<T>.Items.Count > 0)
                {
                    return RelateableBase<T>.Items[0];
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets the last item of the collection.
        /// </summary>
        public T Last
        {
            get
            {
                int myCount = RelateableBase<T>.Items.Count;

                if (myCount > 0)
                {
                    return RelateableBase<T>.Items[myCount - 1];
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets the previous item relative to this one based on the sort order of the collection.
        /// <remarks>
        /// If this item is the oldest, then it returns null.
        /// </remarks>
        /// </summary>
        public T Previous
        {
            get
            {
                T myType = null;
                int myCount = RelateableBase<T>.Items.Count;

                if (myCount > 0)
                {
                    int myPos = RelateableBase<T>.Items.IndexOf((T)(object)this);

                    //only attempt to get the previous item if our item is within the range:  0 < item < item.count
                    //so, if there are 9 entries (0-8) in the collection, ours must be item 1 to 8.
                    if (myPos > 0 && myPos < myCount)
                    {
                        return RelateableBase<T>.Items[myPos -1];
                    }
                }

                return myType;
            }
        }

        /// <summary>
        /// Gets the next item relative to this one based on the sort order of the collection.
        /// <remarks>
        /// If this item is the newest, then it returns null.
        /// </remarks>
        /// </summary>
        public T Next
        {
            get
            {
                T myType = null;
                int myCount = RelateableBase<T>.Items.Count;

                if (myCount > 0)
                {
                    int myPos = RelateableBase<T>.Items.IndexOf(((T)(object)this));

                    //only attempt to get the next item if our item is within the range: 0 <= item < (items.count - 1)
                    //so, if there are 9 entries (0-8) in the collection, ours must be item 0 to 7
                    if (myPos >= 0 && myPos < (myCount - 1))
                    {
                        return RelateableBase<T>.Items[myPos + 1];
                    }
                }

                return myType;
            }
        }

        #endregion

        #region methods
        /// <summary>
        /// Private routine to return items between the two dates depending on visibility.
        /// </summary>
        private static List<T> GetItemsForDateRange(DateTime dateFrom, DateTime dateTo, bool visibleOnly)
        {
            //TODO: remove commented out code when tested
            //List<T> list = new List<T>();
            //foreach (T item in RelateableBase<T>.Items)
            //{
            //    if (item.DateCreated.Date >= dateFrom && item.DateCreated.Date <= dateTo)
            //    {
            //        if (!visibleOnly || (visibleOnly && item.IsVisible))
            //        {
            //            list.Add(item);
            //        }
            //    }
            //}

            List<T> list = RelateableBase<T>.Items.FindAll(delegate(T item)
            {
                return ((item.DateCreated.Date >= dateFrom && item.DateCreated.Date <= dateTo) && (!visibleOnly || (visibleOnly && item.IsVisible)));
            });

            return list;
        } 
        /// <summary>
        /// Returns all items between the two dates.
        /// </summary>
        public static List<T> GetByDate(DateTime dateFrom, DateTime dateTo)
        {
            return GetItemsForDateRange(dateFrom, dateTo, false);
        }
        /// <summary>
        /// Returns all visible items between the two dates.  In other words, published and within the date range. 
        /// </summary>
        public static List<T> GetVisibleByDate(DateTime dateFrom, DateTime dateTo)
        {
            return GetItemsForDateRange(dateFrom, dateTo, true);
        }

        #endregion
    }
}
